<?php

namespace App\Services\Wechat;

use GuzzleHttp\Client;
use Illuminate\Support\Facades\Config;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Str;

class WechatPaymentService
{
    /**
     * 生成微信 JSAPI 支付参数
     */
    public function generateJsConfig($prepayId)
    {
        $appId = $this->config['app_id'];
        $timeStamp = (string)time();
        $nonceStr = Str::random(32);
        $package = 'prepay_id=' . $prepayId;
        $signType = 'RSA';

        // 构造待签名字符串
        $message = $appId . "\n" . $timeStamp . "\n" . $nonceStr . "\n" . $package . "\n";
        $privateKey = file_get_contents($this->config['key_path']);
        openssl_sign($message, $signature, $privateKey, 'sha256WithRSAEncryption');
        $paySign = base64_encode($signature);

        return [
            'appId'     => $appId,
            'timeStamp' => $timeStamp,
            'nonceStr'  => $nonceStr,
            'package'   => $package,
            'signType'  => $signType,
            'paySign'   => $paySign,
        ];
    }
    private $config;
    private $client;
    private $baseUrl = 'https://api.mch.weixin.qq.com/v3';

    public function __construct()
    {
        // 加载微信支付配置
        $this->config = Config::get('wechatpay');
        
        // 临时解决方案：直接设置platform_serial_no
        if (!isset($this->config['platform_serial_no'])) {
            $this->config['platform_serial_no'] = env('WECHATPAY_PLATFORM_SERIAL_NO');
        }
        
        // 修复平台证书路径问题
        if (isset($this->config['platform_certs']) && is_array($this->config['platform_certs'])) {
            $fixedCerts = [];
            foreach ($this->config['platform_certs'] as $certPath) {
                // 如果路径不是绝对路径，则添加storage_path
                if (!str_starts_with($certPath, '/')) {
                    $fixedCerts[] = storage_path($certPath);
                } else {
                    $fixedCerts[] = $certPath;
                }
            }
            $this->config['platform_certs'] = $fixedCerts;
        }
        
        // 调试：记录配置加载情况
        Log::info('WechatPaymentService配置加载', [
            'env_value' => env('WECHATPAY_PLATFORM_SERIAL_NO'),
            'config_value' => config('wechatpay.platform_serial_no'),
            'this_config_keys' => array_keys($this->config),
            'platform_serial_no_in_config' => array_key_exists('platform_serial_no', $this->config),
            'final_platform_serial_no' => $this->config['platform_serial_no'] ?? 'STILL_NULL'
        ]);
        
        // 初始化Guzzle客户端
        $this->client = new Client([
            'timeout' => 30,
            //    'verify' => storage_path('cacert.pem')
            'verify' => true
        ]);
    }

    /**
     * 生成V3签名
     */
    private function generateSign($method, $url, $timestamp, $nonce, $body = '')
    {
        $canonicalUrl = parse_url($url, PHP_URL_PATH);
        if (parse_url($url, PHP_URL_QUERY)) {
            $canonicalUrl .= '?' . parse_url($url, PHP_URL_QUERY);
        }

        $message = $method . "\n"
            . $canonicalUrl . "\n"
            . $timestamp . "\n"
            . $nonce . "\n"
            . $body . "\n";

        // 使用商户私钥进行签名
        $privateKey = file_get_contents($this->config['key_path']);
        openssl_sign($message, $signature, $privateKey, 'sha256WithRSAEncryption');
        return base64_encode($signature);
    }

    /**
     * 创建支付订单
     */
    public function createOrder($orderData)
    {
        $path = '/pay/transactions/jsapi';
        $url = $this->baseUrl . $path;
        $timestamp = (string)time();
        $nonce = Str::random(32);

        // 构建请求体
        $body = json_encode([
            'mchid' => $this->config['mch_id'],
            'out_trade_no' => $orderData['out_trade_no'],
            'appid' => $this->config['app_id'],
            'description' => $orderData['description'],
            'notify_url' => $this->config['notify_url'],
            'amount' => [
                'total' => $orderData['total_amount'],
                'currency' => 'CNY'
            ],
            'payer' => [
                'openid' => $orderData['openid']
            ]
        ]);

        // 生成签名
        $signature = $this->generateSign('POST', $url, $timestamp, $nonce, $body);

        // 构建Authorization头
        $authorization = sprintf(
            'WECHATPAY2-SHA256-RSA2048 mchid="%s",serial_no="%s",timestamp="%s",nonce_str="%s",signature="%s"',
            $this->config['mch_id'],
            $this->config['serial_no'],
            $timestamp,
            $nonce,
            $signature
        );

        try {
            // 发送请求
            $response = $this->client->post($url, [
                'headers' => [
                    'Authorization' => $authorization,
                    'Content-Type' => 'application/json',
                    'Accept' => 'application/json'
                ],
                'body' => $body
            ]);

            $result = json_decode($response->getBody(), true);
            return $result;
        } catch (\Exception $e) {
            Log::error('创建微信支付订单失败: ' . $e->getMessage());
            throw new \Exception('创建支付订单失败');
        }
    }

    /**
     * 处理支付回调
     */
    public function handleNotify($request)
    {
        // 获取原始内容
        $data = $request->getContent();
        // 获取微信回调头部
        $timestamp = $request->header('Wechatpay-Timestamp');
        $nonce = $request->header('Wechatpay-Nonce');
        $signature = $request->header('Wechatpay-Signature');
        $serial = $request->header('Wechatpay-Serial');

        Log::info('微信支付回调数据: ' . $data);
        Log::info('微信支付回调头信息: ', [
            'Wechatpay-Timestamp' => $timestamp,
            'Wechatpay-Nonce' => $nonce,
            'Wechatpay-Signature' => $signature,
            'Wechatpay-Serial' => $serial,
        ]);

        // 校验证书序列号
        Log::info('调试配置信息', [
            'config_keys' => array_keys($this->config),
            'platform_serial_no_exists' => array_key_exists('platform_serial_no', $this->config),
            'platform_serial_no_value' => $this->config['platform_serial_no'] ?? 'NOT_FOUND',
            'full_config' => $this->config
        ]);
        
        if ($serial !== ($this->config['platform_serial_no'] ?? null)) {
            throw new \Exception('证书序列号不匹配。收到: ' . $serial . ', 期望: ' . ($this->config['platform_serial_no'] ?? 'NULL'));
        }

        // 构造签名串
        $message = $timestamp . "\n" . $nonce . "\n" . $data . "\n";

        // 验证签名
        Log::info('平台证书路径调试', [
            'platform_certs_array' => $this->config['platform_certs'],
            'first_cert_path' => $this->config['platform_certs'][0],
            'file_exists' => file_exists($this->config['platform_certs'][0])
        ]);
        
        $platformCert = file_get_contents($this->config['platform_certs'][0]);
        $publicKey = openssl_pkey_get_public($platformCert);
        $verifyResult = openssl_verify($message, base64_decode($signature), $publicKey, 'sha256WithRSAEncryption');
        if ($verifyResult !== 1) {
            throw new \Exception('签名验证失败');
        }

        // 解析回调数据
        $notifyData = json_decode($data, true);
        if (!isset($notifyData['resource']['ciphertext'])) {
            throw new \Exception('回调数据格式错误');
        }

        // 解密数据
        $associatedData = $notifyData['resource']['associated_data'] ?? '';
        $nonceStr = $notifyData['resource']['nonce'];
        $ciphertext = $notifyData['resource']['ciphertext'];

        $decrypted = $this->decryptData($associatedData, $nonceStr, $ciphertext);
        return json_decode($decrypted, true);
    }

    /**
     * 解密回调数据
     */
    private function decryptData($associatedData, $nonce, $ciphertext)
    {
        // 微信支付V3解密密钥：直接使用32位APIv3密钥
        $key = $this->config['api_key'];
        
        // 记录解密调试信息
        Log::info('解密参数调试', [
            'key_length' => strlen($key),
            'nonce_length' => strlen($nonce),
            'associated_data' => $associatedData,
            'ciphertext_base64_length' => strlen($ciphertext)
        ]);
        
        $ciphertext = base64_decode($ciphertext);
        
        // 检查解密后的密文长度
        if (strlen($ciphertext) < 16) {
            throw new \Exception('密文长度不足，无法提取认证标签');
        }

        // 使用AEAD_AES_256_GCM算法解密
        $tagLength = 16;
        $ciphertextWithoutTag = substr($ciphertext, 0, -$tagLength);
        $tag = substr($ciphertext, -$tagLength);
        
        Log::info('解密组件长度', [
            'ciphertext_total_length' => strlen($ciphertext),
            'ciphertext_without_tag_length' => strlen($ciphertextWithoutTag),
            'tag_length' => strlen($tag)
        ]);

        $plaintext = openssl_decrypt(
            $ciphertextWithoutTag,
            'aes-256-gcm',
            $key,
            OPENSSL_RAW_DATA,
            $nonce,
            $tag,
            $associatedData
        );

        if ($plaintext === false) {
            $error = openssl_error_string();
            Log::error('OpenSSL解密详细错误', [
                'error' => $error,
                'key_used' => substr($key, 0, 8) . '...', // 只记录密钥前8位用于调试
                'nonce' => $nonce,
                'associated_data' => $associatedData
            ]);
            throw new \Exception('解密失败: ' . $error);
        }

        Log::info('解密成功', ['plaintext_length' => strlen($plaintext)]);
        return $plaintext;
    }

    /**
     * 查询订单状态
     */
    public function queryOrder($outTradeNo)
    {
        $path = "/pay/transactions/out-trade-no/{$outTradeNo}?mchid={$this->config['mch_id']}";
        $url = $this->baseUrl . $path;
        $timestamp = (string)time();
        $nonce = Str::random(32);

        // 生成签名
        $signature = $this->generateSign('GET', $url, $timestamp, $nonce);

        // 构建Authorization头
        $authorization = sprintf(
            'WECHATPAY2-SHA256-RSA2048 mchid="%s",serial_no="%s",timestamp="%s",nonce_str="%s",signature="%s"',
            $this->config['mch_id'],
            $this->config['serial_no'],
            $timestamp,
            $nonce,
            $signature
        );

        try {
            // 发送请求
            $response = $this->client->get($url, [
                'headers' => [
                    'Authorization' => $authorization,
                    'Accept' => 'application/json'
                ]
            ]);

            return json_decode($response->getBody(), true);
        } catch (\Exception $e) {
            Log::error('查询微信支付订单失败: ' . $e->getMessage());
            throw new \Exception('查询订单失败');
        }
    }
}
